package network.server;

import common.util.DBUtil;
import lombok.Getter;
import network.server.handler.initAllHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 服务器主类
 * <p>
 * 负责启动、停止、重启服务器，
 * 并通过线程池处理所有客户端连接。
 * 每个客户端连接都会创建一个 {@link ClientHandler} 来处理请求。
 */
public class ServerMain {
    private static final Logger logger = LoggerFactory.getLogger(ServerMain.class);

    private final int port;
    private final RequestDispatcher dispatcher;
    private ServerSocket serverSocket;
    private ExecutorService threadPool;

    /** 服务器运行状态 */
    @Getter
    private volatile boolean running = false;

    /**
     * 构造函数
     *
     * @param port       服务器监听端口
     * @param dispatcher 请求分发器
     */
    public ServerMain(int port, RequestDispatcher dispatcher) {
        this.port = port;
        this.dispatcher = dispatcher;
    }

    /**
     * 启动服务器
     *
     * @throws IOException 可能抛出套接字创建异常
     */
    public void start() throws IOException {
        serverSocket = new ServerSocket(port);
        int poolSize = Runtime.getRuntime().availableProcessors() * 2;
        threadPool = Executors.newFixedThreadPool(poolSize);

        running = true;
        logger.info("服务器启动成功，监听端口: {}", port);

        Thread acceptorThread = new Thread(this::acceptConnections, "Acceptor-Thread");
        acceptorThread.start();
    }

    /**
     * 接受客户端连接
     */
    private void acceptConnections() {
        while (running) {
            try {
                Socket clientSocket = serverSocket.accept();
                logger.info("接收到客户端连接: {}", clientSocket.getRemoteSocketAddress());

                ClientHandler clientHandler = new ClientHandler(clientSocket, this.dispatcher);
                threadPool.execute(clientHandler);

            } catch (IOException e) {
                if (running) {
                    logger.error("接受连接时发生错误: {}", e.getMessage());
                } else {
                    logger.info("服务器已停止接受新连接");
                }
            }
        }
    }

    /**
     * 停止服务器，优雅关闭线程池和套接字
     */
    public void stop() {
        running = false;
        logger.info("正在停止服务器...");

        try {
            if (serverSocket != null && !serverSocket.isClosed()) {
                serverSocket.close();
            }
        } catch (IOException e) {
            logger.error("关闭服务器套接字时发生错误: {}", e.getMessage());
        }

        if (threadPool != null) {
            threadPool.shutdown();
            try {
                if (!threadPool.awaitTermination(30, TimeUnit.SECONDS)) {
                    logger.warn("线程池未在指定时间内关闭，强制终止");
                    threadPool.shutdownNow();
                }
            } catch (InterruptedException e) {
                logger.warn("等待线程池关闭时被中断");
                threadPool.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }

        logger.info("服务器已停止");
    }

    /**
     * 优雅重启服务器
     *
     * @throws IOException 可能抛出启动异常
     */
    public void restart() throws IOException {
        stop();
        start();
    }

    /**
     * 服务器启动入口
     *
     * @param args 命令行参数
     */
    public static void main(String[] args) {
        initAllHandler initial = new initAllHandler();
        initial.init();

        RequestDispatcher dispatcher = RequestDispatcher.getInstance();

        Properties props = new Properties();
        try (InputStream input = ServerMain.class.getClassLoader().getResourceAsStream("threadPool.properties")) {
            if (input == null) {
                logger.error("找不到配置文件: threadPool.properties");
            } else {
                props.load(input);
                logger.info("成功加载线程池配置文件");
            }
        } catch (IOException e) {
            logger.error("读取配置文件失败: {}", e.getMessage());
        }

        ServerMain server = new ServerMain(Integer.parseInt(props.getProperty("threadPool.port")), dispatcher);

        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            logger.info("接收到关闭信号，正在停止服务器...");
            server.stop();
        }));

        try {
            server.start();
            while (server.isRunning()) {
                Thread.sleep(1000);
            }
        } catch (IOException e) {
            logger.error("启动服务器失败: {}", e.getMessage());
            System.exit(1);
        } catch (InterruptedException e) {
            logger.info("主线程被中断");
            Thread.currentThread().interrupt();
        }
    }
}
